import React, { PureComponent } from 'react';
import cx from 'classnames';
import Slider from 'darmody-react-slick';
import PropTypes from 'prop-types';

import { getWebpSrc } from 'modules/image';
import previewImage from 'modules/previewImage';
import VideoPlayer from 'modules/VideoPlay/new';

import MaskLayerComponent from './MaskLayer';

import './slick.less';
import styles from './styles.less';

/** item 可用类型
    IMAGE: 元素需满足格式 { type: 'image', url: '图片地址' }
    VEDIO: 元素需满足格式 { type: 'video', url: '视频地址', posterAvatar: '作者头像地址' }
*/
export const SLIDE_TYPES = {
    IMAGE: 'image',
    VIDEO: 'video',
};

export default class Carousel extends PureComponent {
    static defaultProps = {
        children: null,
        data: [],
        MaskLayer: null,
        wrapperClassName: '',
        mainClassName: '',
        itemClassName: '',
        renderItem: null,

        // 组件默认属性，具体查看 https://github.com/darmody/react-slick
        afterChange: null,
        initialSlide: 0,
        arrows: false,
        dots: true,
        infinite: false,
        slidesToShow: 1,
        slidesToScroll: 1,
        touchThreshold: 3, // 滑动生效距离，3 表示 1/3
        fade: false,
        speed: 300,
        cssEase: '', // 禁用效果, 避免快速滑动时抖动
        easing: '',
        previewImage: true, // 是否开启图片预览
        CarouselPageComponent: null, // 自定义页码
        preloadList: [],
        showArrows: '',
        forceShowDots: false,
        firstImg: '',
        backgroundSize: 'cover',
    };

    static propTypes = {
        // 如果传入了子元素，则会渲染子元素。用于完全的自定义, 包括懒加载都需要自己实现
        children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
        // 轮播要展示的数据数组, 元素格式查看上面的 SLIDE_TYPE 类型说明
        data: PropTypes.arrayOf(PropTypes.shape({})),
        // 浮层组件
        MaskLayer: PropTypes.func,
        // 滚动之后的回调
        afterChange: PropTypes.func,
        // 初始元素下标
        initialSlide: PropTypes.number,
        // 是否显示 点点点
        dots: PropTypes.bool,
        // 是否强制显示 点点点
        forceShowDots: PropTypes.bool,
        // warpper层class
        wrapperClassName: PropTypes.string,
        // main层class
        mainClassName: PropTypes.string,
        // item 的 class
        itemClassName: PropTypes.string,
        // 自定义元素渲染
        renderItem: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
        // 是否显示箭头
        arrows: PropTypes.bool,
        // 是否循环轮播
        infinite: PropTypes.bool,
        // 显示的 item 个数
        slidesToShow: PropTypes.number,
        // 单次轮播的 item 个数
        slidesToScroll: PropTypes.number,
        // 滑动生效阈值
        touchThreshold: PropTypes.number,
        // 渐变效果是否启用
        fade: PropTypes.bool,
        // 滑动速度
        speed: PropTypes.number,
        // css easing 效果
        cssEase: PropTypes.string,
        easing: PropTypes.string,
        previewImage: PropTypes.bool,
        // 自定义页码
        CarouselPageComponent: PropTypes.node,
        preloadList: PropTypes.arrayOf(PropTypes.number),
        showArrows: PropTypes.string,
        firstImg: PropTypes.string,
        backgroundSize: PropTypes.string,
        wrapStyle: PropTypes.object, // 内联样式
    };

    state = {
        preloadList: this.props.preloadList || [],
        currentPage: 1,
    };

    mounted = false;

    componentDidMount() {
        this.preLoad(this.props.initialSlide);
        this.setMounted();
    }

    setMounted = () => {
        setTimeout(() => {
            this.setState({
                mounted: true,
            });
        }, 200);
    };

    handlePreviewImage = (item) => () => {
        const getOriginImage = (image = '') => image.replace(/\/w\/[0-9]+$/, '');
        const current = getOriginImage(item.url || item.img || '');
        const data = this.props.data.slice();
        if (this.props.firstImg) {
            data.splice(0, 1, { url: this.props.firstImg, type: SLIDE_TYPES.IMAGE });
        }
        const urls = data
            .filter((i) => i.type === SLIDE_TYPES.IMAGE)
            .map((image) => getOriginImage(image.url || image.img || ''));

        this.props.previewImage &&
            previewImage({
                current,
                urls,
            });
    };

    handleAfterChange = (index) => {
        this.preLoad(index);
        this.setState({
            currentPage: index + 1,
        });

        if (this.props.afterChange) {
            let item = null;

            if (this.props.data && this.props.data.length > 0) {
                item = this.props.data[index];
            }
            this.props.afterChange(index, item);
        }
    };

    preLoad = (index) => {
        // 预加载当前元素及其前后元素
        let { preloadList } = this.state;
        const { data } = this.props;

        // 已经全部加载了
        if (preloadList.length === data.length) {
            return;
        }

        [index - 1, index, index + 1].forEach((item) => {
            if (item < 0 || item >= data.length) {
                return;
            }

            if (preloadList.find((preloadIndex) => preloadIndex === item) === undefined) {
                preloadList = [...preloadList, item];
            }
        });

        this.setState({
            preloadList,
        });
    };

    // pc端显示轮播箭头
    showArrows = () => WPT.os.device === 'web-pc' && this.props.showArrows !== 'not-show';

    // 是否显示点点点
    showDots = () => this.props.dots && (this.props.forceShowDots || !this.onlyOne());

    // 是否只有一个轮播元素
    onlyOne = () => {
        const { data, children } = this.props;

        if (children) {
            return children.length === 1;
        }

        return data && data.length === 1;
    };

    setRef = (container) => {
        this.sliderRef = container;
        this.slickGoTo = (...params) => container.slickGoTo(...params);
    };

    renderImage = (item) => (
        <LazyImage
            className={cx(styles.slideItem, this.props.itemClassName)}
            src={item.url || item.img}
            style={{
                backgroundImage: `url(${getWebpSrc(item.url || item.img)})`,
                backgroundPosition: 'center',
                backgroundRepeat: 'no-repeat',
                backgroundSize: this.props.backgroundSize,
            }}
            onClick={this.handlePreviewImage(item)}
            role="presentation"
            hasBlur={false}
        />
    );

    renderVideo = (item) => (
        <div className={cx(styles.slideItem, this.props.itemClassName)}>
            <VideoPlayer src={item.url} poster={getWebpSrc(item.posterAvatar)} isPreload />
        </div>
    );

    renderSlideContainer = (slide, index) => {
        const { renderItem, data } = this.props;
        const { preloadList } = this.state;

        const Slide = renderItem || this.renderSlide;
        // 不在预加载列表里不 render
        if (preloadList.find((item) => item === index) === undefined) {
            return <div className={styles.slideContainer} key={`${slide.url || slide.img}${index}`} />;
        }

        return (
            // 修改图片尺寸时不卸载组件
            <div
                className={styles.slideContainer}
                key={`${(slide.url || slide.img)?.replace(/\/w\/\d+$/i, '')}-${index}`}
            >
                <div className={styles.slideItemWrapper}>
                    <Slide item={slide} index={index} data={data} preloadList={preloadList} />
                </div>
            </div>
        );
    };

    renderCustomPageNum = () => {
        const { currentPage } = this.state;
        const { data, CarouselPageComponent } = this.props;
        if (!CarouselPageComponent) {
            return null;
        }
        return <CarouselPageComponent currentPage={currentPage} pageNum={data.length} />;
    };

    renderSlide = ({ item: slide }) => {
        switch (slide.type) {
            case SLIDE_TYPES.VIDEO:
                return this.renderVideo(slide);
            case SLIDE_TYPES.IMAGE:
            default:
                return this.renderImage(slide);
        }
    };

    renderSlides = () => {
        const { data, children } = this.props;

        if (children) {
            return children;
        }

        return data.map(this.renderSlideContainer);
    };

    renderMaskLayer = () => {
        const { MaskLayer } = this.props;

        if (MaskLayer) {
            return <MaskLayer dotsHidden={!this.showDots()} />;
        }

        return null;
    };

    render() {
        const { wrapperClassName, mainClassName, wrapStyle = {}, ...settings } = this.props;

        const { mounted } = this.state;

        const dotsHiddenClass = this.showDots() ? '' : styles.dotsHidden;

        return (
            <div className={cx(styles.sliderWrapper, dotsHiddenClass, wrapperClassName, mounted ? styles.mounted : '')}>
                <div className={cx(styles.sliderMain, mainClassName)} style={wrapStyle}>
                    <Slider
                        ref={this.setRef}
                        {...settings}
                        lazyLoad={false} // 他们的 lazyload 实现有问题，不要启用
                        arrows={this.showArrows()}
                        afterChange={this.handleAfterChange}
                    >
                        {this.renderSlides()}
                    </Slider>
                    {this.renderMaskLayer()}
                    {this.renderCustomPageNum()}
                </div>
            </div>
        );
    }
}

// 默认提供一个公共浮层
export { MaskLayerComponent as MaskLayer };
